package server

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"time"
	"github.com/go-pg/pg/v10"
	"github.com/minio/minio-go/v6"
	"github.com/redis/go-redis/v9"
	"github.com/spf13/viper"
	log "github.com/sirupsen/logrus"
)

var timerList map[string]*time.Timer

type dataSources struct {
	DB           *pg.DB
	RedisClient  *redis.Client
	MinioClient  *minio.Client
}

func initDS() (*dataSources, error) {
	
	viper.SetConfigFile(".env")
	// Find and read the config file
	if err := viper.ReadInConfig(); err != nil {
		return nil, fmt.Errorf("error reading .env setting")
	}
	// db engine initialize

	//pgHost := viper.Get("PG_HOST").(string)
	pgPort := viper.Get("PG_PORT").(string)
	pgUser := viper.Get("PG_USER").(string)
	pgPassword := viper.Get("PG_PASSWORD").(string)
	pgDB := viper.Get("PG_DB").(string)
	//pgSSL := viper.Get("PG_SSL").(string)

	db := pg.Connect(&pg.Options{
		Addr:     ":"+pgPort,
		User:     pgUser,
		Password: pgPassword,
		Database: pgDB,
	})

	ctx := context.Background()

	// Verify database connection is working
	if err := db.Ping(ctx); err != nil {
		return nil, fmt.Errorf("error connecting to db: %w", err)
	}	

	// redis initialize

	return &dataSources{
		DB:            db,
		RedisClient:   nil,
		MinioClient: nil,
	}, nil
}

func Start() error {
	// logger initialize


	// service factory initialize
	// initialize data sources
	ds, err := initDS()

	if err != nil {
		log.Fatalf("Unable to initialize data sources: %v\n", err)
	}

	router, err := inject(ds)

	if err != nil {
		log.Fatalf("Failure to inject data sources: %v\n", err)
	}

	ip := "0.0.0.0"
	port := "8080"

	srv := &http.Server{
		Addr: fmt.Sprintf("%v:%v", ip, port),
		Handler: router,
	}

	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	shutdownTimeout := 5
	// Wait for "interrupt" or "kill" signal to gracefully shutdown.
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt, os.Kill)
	sig := <-quit

	log.Printf("Shutdown Server with Signal %v", sig)

	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(shutdownTimeout)*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	log.Println("Server exiting")

	return nil
}